# Copyright (c) <2021> Side Effects Software Inc.
#  All rights reserved.
#
#  Redistribution and use in source and binary forms, with or without
#  modification, are permitted provided that the following conditions are met:
#
#  1. Redistributions of source code must retain the above copyright notice,
#     this list of conditions and the following disclaimer.
#
#  2. The name of Side Effects Software may not be used to endorse or
#     promote products derived from this software without specific prior
#     written permission.
#
#  THIS SOFTWARE IS PROVIDED BY SIDE EFFECTS SOFTWARE "AS IS" AND ANY EXPRESS
#  OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
#  OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
#  NO EVENT SHALL SIDE EFFECTS SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT,
#  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
#  LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
#  OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
#  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
#  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
#  EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

import unreal

""" Example script for instantiating an asset, cooking it and baking all of
its outputs.

"""

_g_wrapper = None


def get_test_hda_path():
    return '/HoudiniEngine/Examples/hda/pig_head_subdivider_v01.pig_head_subdivider_v01'


def get_test_hda():
    return unreal.load_object(None, get_test_hda_path())


def on_post_instantiation(in_wrapper):
    print('on_post_instantiation')
    # in_wrapper.on_post_instantiation_state_exited_delegate_delegate.remove_callable(on_post_instantiation)

    # Set parameter values for the next cook
    # in_wrapper.set_bool_parameter_value('add_instances', True)
    # in_wrapper.set_int_parameter_value('num_instances', 8)
    in_wrapper.set_parameter_tuples({
        'add_instances': unreal.HoudiniParameterTuple(bool_values=(True, )),
        'num_instances': unreal.HoudiniParameterTuple(int32_values=(8, )),
    })
    
    # Print all parameter values
    param_tuples = in_wrapper.get_parameter_tuples()
    print('parameter tuples: {}'.format(len(param_tuples) if param_tuples else 0))
    if param_tuples:
        for param_tuple_name, param_tuple in param_tuples.items():
            print('parameter tuple name: {}'.format(param_tuple_name))
            print('\tbool_values: {}'.format(param_tuple.bool_values))
            print('\tfloat_values: {}'.format(param_tuple.float_values))
            print('\tint32_values: {}'.format(param_tuple.int32_values))
            print('\tstring_values: {}'.format(param_tuple.string_values))

    # Force a cook/recook
    in_wrapper.recook()


def on_post_bake(in_wrapper, success):
    in_wrapper.on_post_bake_delegate.remove_callable(on_post_bake)
    print('bake complete ... {}'.format('success' if success else 'failed'))

    # Delete the hda after the bake
    in_wrapper.delete_instantiated_asset()
    global _g_wrapper
    _g_wrapper = None


def on_post_process(in_wrapper):
    print('on_post_process')

    # in_wrapper.on_post_processing_delegate.remove_callable(on_post_process)

    # Print out all outputs generated by the HDA
    num_outputs = in_wrapper.get_num_outputs()
    print('num_outputs: {}'.format(num_outputs))
    if num_outputs > 0:
        for output_idx in range(num_outputs):
            identifiers = in_wrapper.get_output_identifiers_at(output_idx)
            print('\toutput index: {}'.format(output_idx))
            print('\toutput type: {}'.format(in_wrapper.get_output_type_at(output_idx)))
            print('\tnum_output_objects: {}'.format(len(identifiers)))
            if identifiers:
                for identifier in identifiers:
                    output_object = in_wrapper.get_output_object_at(output_idx, identifier)
                    output_component = in_wrapper.get_output_component_at(output_idx, identifier)
                    is_proxy = in_wrapper.is_output_current_proxy_at(output_idx, identifier)
                    print('\t\tidentifier: {}'.format(identifier))
                    print('\t\toutput_object: {}'.format(output_object.get_name() if output_object else 'None'))
                    print('\t\toutput_component: {}'.format(output_component.get_name() if output_component else 'None'))
                    print('\t\tis_proxy: {}'.format(is_proxy))
                    print('')

    # bind to the post bake delegate
    in_wrapper.on_post_bake_delegate.add_callable(on_post_bake)

    # Bake all outputs to actors
    print('baking all outputs to actors')
    in_wrapper.bake_all_outputs_with_settings(
        unreal.HoudiniEngineBakeOption.TO_ACTOR,
        replace_previous_bake=False,
        remove_temp_outputs_on_success=False)


def run():
    # get the API singleton
    api = unreal.HoudiniPublicAPIBlueprintLib.get_api()

    global _g_wrapper

    # instantiate an asset, disabling auto-cook of the asset (so we have to
    # call wrapper.reCook() to cook it)
    _g_wrapper = api.instantiate_asset(get_test_hda(), unreal.Transform(), enable_auto_cook=False)

    # Bind to the on post instantiation delegate (before the first cook)
    _g_wrapper.on_post_instantiation_delegate.add_callable(on_post_instantiation)
    # Bind to the on post processing delegate (after a cook and after all
    # outputs have been generated in Unreal)
    _g_wrapper.on_post_processing_delegate.add_callable(on_post_process)


if __name__ == '__main__':
    run()
